// Thud - a dynamic object-oriented language
// Copyright (C) 2009,2010 David H. Hovemeyer <david.hovemeyer@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

/*
 * Method.h
 *
 *  Created on: Nov 24, 2009
 *      Author: dhovemey
 */

#ifndef METHOD_H_
#define METHOD_H_

#include <string>
#include <vector>
#include <cstdint>
#include <cstdio>
#include "vm/IPersistent.h"

class Method : public IPersistent {
private:
	typedef std::vector<std::wstring> ParamMap;

	std::wstring m_name;
	uint8_t* m_code;
	uint32_t m_numBytes;
	uint32_t m_codeCapacity;
	uint32_t m_flags;
	ParamMap m_paramMap;
	uint8_t m_numLocals;

	Method(const Method &);
	Method& operator=(const Method &);

public:
	/** Default constructor. */
	Method();

	/**
	 * Constructor.
	 * @param name the name of the method
	 */
	Method(const std::wstring &name);

	/** Destructor. */
	~Method();

	/** Get the name of the method. */
	const std::wstring &getName() const;

	/**
	 * Set method flags.
	 * @param flags the flags to set
	 */
	void setFlags(uint32_t flags) { m_flags = flags; }

	/**
	 * Get method flags.
	 */
	uint32_t getFlags() const { return m_flags; }

	/**
	 * Get the number of code bytes.
	 */
	int getNumBytes() const;

	/**
	 * Get the bytecode (containing the method's instructions).
	 */
	const uint8_t *getCode() const;

	/**
	 * Add a parameter to the method.
	 *
	 * @param varName the parameter to add
	 */
	void addParam(const std::wstring &varName);

	/**
	 * Get the number of parameters that the method has.
	 * Note that the receiver object ("self") is considered to be a parameter.
	 */
	unsigned getNumParams() const { return unsigned(m_paramMap.size()); }

	/**
	 * Set the number of local variables that a method has.
	 * Note that this includes the receiver object ("self"), all of the
	 * explicit method parameters, and all local variables used within the method.
	 *
	 * @param numLocals number of local variables
	 */
	void setNumLocals(uint8_t numLocals) { m_numLocals = numLocals; }

	/**
	 * Get the number of local variables.
	 * Includes receiver object ("self"), explicit parameters,
	 * and local variables used within the method.
	 */
	uint8_t getNumLocals() const { return m_numLocals; }

	/**
	 * Get name of a parameter.
	 *
	 * @param index parameter index (0 for receiver object, 1 for first explicit parameter)
	 */
	const std::wstring &getParam(int index) const;

	/**
	 * Freeze the method.
	 * No more bytecode instructions can be added once method is frozen.
	 */
	void freeze();

	/**
	 * Append a code byte.
	 * @param b the code byte to append
	 */
	void append(uint8_t b);

	/**
	 * Set given code byte.
	 * @param i offset of code byte to set
	 * @param b the code byte to set
	 */
	void setByte(uint32_t i, uint8_t b);

	void read(DataInputStream *in);
	void write(DataOutputStream *out) const;

private:
	void grow(uint32_t size);
	void reallocate(uint32_t size);
};

#endif /* METHOD_H_ */
